"""
ASR (Automatic Speech Recognition) 语音识别服务
基于Qwen3-ASR模型进行语音转文本
使用DashScope SDK
"""

import asyncio
import json
import time
import os
import base64
from typing import Dict, Any, Optional
import dashscope
from config.settings import config
from utils.logger import (
    emobot_logger,
    log_function_call,
    log_function_result,
    log_function_error,
)
from utils.performance_logger import (
    log_api_call,
    track_step
)

logger = emobot_logger.get_logger()


class ASRService:
    """Qwen3-ASR语音识别服务 - 使用DashScope SDK"""
    
    def __init__(self):
        self.api_key = getattr(config, 'ASR_API_KEY', None)
        self.model = getattr(config, 'ASR_MODEL', 'qwen3-asr-flash')
        
        # API限流监控
        self.rate_limit_count = 0
        self.last_rate_limit_time = 0
        self.rate_limit_threshold = 5  # 5次限流后提醒
        
        # 设置DashScope API Key
        if self.api_key:
            os.environ['DASHSCOPE_API_KEY'] = self.api_key
            dashscope.api_key = self.api_key
        else:
            logger.warning("ASR_API_KEY not configured, ASR service will not work")
    
    async def recognize_audio_file(self, audio_file_path: str, task_id: str = None) -> Dict[str, Any]:
        """
        识别音频文件并返回文本结果
        
        Args:
            audio_file_path: 音频文件路径
            task_id: 任务ID，用于日志追踪
            
        Returns:
            Dict包含识别结果
        """
        start_time = time.time()
        log_function_call("ASRService.recognize_audio_file", {
            "audio_file_path": audio_file_path,
            "task_id": task_id
        })
        
        try:
            if not os.path.exists(audio_file_path):
                raise FileNotFoundError(f"Audio file not found: {audio_file_path}")
            
            # 检查文件大小
            file_size = os.path.getsize(audio_file_path)
            if file_size == 0:
                raise ValueError("Audio file is empty")
            
            logger.info(f"Starting ASR recognition for file: {audio_file_path}, size: {file_size} bytes")
            
            # 检查音频文件基本信息
            try:
                import wave
                with wave.open(audio_file_path, 'rb') as wav_file:
                    frames = wav_file.getnframes()
                    sample_rate = wav_file.getframerate()
                    channels = wav_file.getnchannels()
                    duration = frames / float(sample_rate)
                    logger.info(f"音频信息 - 采样率: {sample_rate}Hz, 声道: {channels}, 时长: {duration:.2f}s, 帧数: {frames}")
                    
                    # 检查音频时长是否太短
                    if duration < 0.5:
                        logger.warning(f"音频时长过短: {duration:.2f}s，可能影响识别效果")
                        # 对于过短的音频，建议用户延长录音时间
                        return {
                            "task_id": task_id,
                            "text": "",
                            "confidence": 0.0,
                            "duration": duration,
                            "timestamp": time.time(),
                            "error": "音频时长过短，建议录音时间至少0.5秒",
                            "success": False,
                            "suggestion": "请延长录音时间后重试"
                        }
                    elif duration > 60:
                        logger.warning(f"音频时长过长: {duration:.2f}s，可能影响处理性能")
                    
                    # 检查采样率是否合适
                    if sample_rate < 8000:
                        logger.warning(f"采样率过低: {sample_rate}Hz，建议使用16kHz或更高")
                    elif sample_rate > 48000:
                        logger.warning(f"采样率过高: {sample_rate}Hz，可能影响处理速度")
                    
                    # 检查声道数
                    if channels > 1:
                        logger.warning(f"多声道音频: {channels}声道，建议使用单声道以提高识别效果")
            except Exception as e:
                logger.warning(f"无法读取音频文件信息: {e}")
            
            # 记录ASR API调用
            log_api_call(
                api_name="QWEN3_ASR_DASHSCOPE",
                api_type="ASR",
                request_data={
                    "audio_file_path": audio_file_path,
                    "file_size": file_size,
                    "task_id": task_id,
                    "model": self.model
                }
            )
            
            # 调用DashScope ASR API
            result = await self._call_dashscope_asr_file(audio_file_path, task_id)
            
            duration = (time.time() - start_time) * 1000
            log_function_result("ASRService.recognize_audio_file", result, duration)
            logger.info(f"ASR recognition completed in {duration:.2f}ms")
            
            return result
            
        except Exception as e:
            duration = (time.time() - start_time) * 1000
            log_function_error("ASRService.recognize_audio_file", e, {
                "audio_file_path": audio_file_path,
                "task_id": task_id
            })
            logger.error(f"ASR recognition failed: {e}")
            
            # 返回错误结果
            return {
                "task_id": task_id,
                "text": "",
                "confidence": 0.0,
                "duration": 0.0,
                "timestamp": time.time(),
                "error": str(e),
                "success": False
            }
    
    async def _call_dashscope_asr_file(self, audio_file_path: str, task_id: str = None) -> Dict[str, Any]:
        """使用DashScope SDK调用ASR API，支持限流重试"""
        
        if not self.api_key:
            raise ValueError("ASR API key not configured")
        
        # 重试配置
        max_retries = 3
        retry_delay = 2  # 初始延迟2秒
        backoff_factor = 2  # 指数退避因子
        
        # 读取音频文件并转换为base64
        with open(audio_file_path, 'rb') as audio_file:
            audio_data = audio_file.read()
            audio_base64 = base64.b64encode(audio_data).decode('utf-8')
        
        # 构建消息
        messages = [
            {
                "role": "system",
                "content": [
                    {"text": ""},  # 系统提示词
                ]
            },
            {
                "role": "user",
                "content": [
                    {"audio": f"data:audio/wav;base64,{audio_base64}"},
                ]
            }
        ]
        
        # 重试机制处理API限流
        for attempt in range(max_retries):
            try:
                logger.info(f"尝试调用DashScope API (第{attempt + 1}次)")
                
                # 调用DashScope API
                response = dashscope.MultiModalConversation.call(
                    api_key=self.api_key,
                    model=self.model,
                    messages=messages,
                    result_format="message",
                    asr_options={
                        "enable_lid": True,  # 启用语言检测
                        "enable_itn": False  # 禁用逆文本规范化
                    }
                )
                
                # 检查响应状态
                if response.status_code == 200:
                    logger.info(f"DashScope API调用成功 (第{attempt + 1}次)")
                    return self._parse_dashscope_response(response, audio_file_path, task_id)
                elif response.status_code == 429:
                    # API限流，需要重试
                    self.rate_limit_count += 1
                    self.last_rate_limit_time = time.time()
                    
                    # 检查是否需要提醒用户
                    if self.rate_limit_count >= self.rate_limit_threshold:
                        logger.error(f"API限流频繁发生 ({self.rate_limit_count}次)，建议检查API配额或降低调用频率")
                    
                    if attempt < max_retries - 1:
                        wait_time = retry_delay * (backoff_factor ** attempt)
                        logger.warning(f"API限流，等待{wait_time}秒后重试 (第{attempt + 1}次，累计限流{self.rate_limit_count}次)")
                        await asyncio.sleep(wait_time)
                        continue
                    else:
                        raise Exception(f"API限流，已达到最大重试次数 {max_retries}，累计限流{self.rate_limit_count}次")
                else:
                    # 其他错误，直接抛出
                    raise Exception(f"DashScope API error {response.status_code}: {response.message}")
                    
            except Exception as e:
                if attempt < max_retries - 1:
                    wait_time = retry_delay * (backoff_factor ** attempt)
                    logger.warning(f"API调用失败，等待{wait_time}秒后重试: {e}")
                    await asyncio.sleep(wait_time)
                else:
                    raise e
        
        # 如果所有重试都失败
        raise Exception(f"API调用失败，已达到最大重试次数 {max_retries}")
    
    def get_rate_limit_status(self) -> Dict[str, Any]:
        """获取API限流状态"""
        return {
            "rate_limit_count": self.rate_limit_count,
            "last_rate_limit_time": self.last_rate_limit_time,
            "rate_limit_threshold": self.rate_limit_threshold,
            "is_frequent_limit": self.rate_limit_count >= self.rate_limit_threshold
        }
    
    def reset_rate_limit_count(self):
        """重置限流计数器"""
        self.rate_limit_count = 0
        self.last_rate_limit_time = 0
        logger.info("API限流计数器已重置")
    
    def _parse_dashscope_response(self, response, audio_file_path: str, task_id: str = None) -> Dict[str, Any]:
        """解析DashScope ASR API响应"""
        
        try:
            # 计算音频时长
            import wave
            with wave.open(audio_file_path, 'rb') as wav_file:
                frames = wav_file.getnframes()
                sample_rate = wav_file.getframerate()
                duration = frames / float(sample_rate)
        except:
            duration = 0.0
        
        # 检查响应状态
        if response.status_code != 200:
            raise Exception(f"DashScope API error {response.status_code}: {response.message}")
        
        # 解析响应内容
        text = ""
        confidence = 0.0
        
        # 添加详细的调试日志
        logger.info(f"DashScope API响应状态: {response.status_code}")
        logger.info(f"响应对象类型: {type(response)}")
        logger.info(f"响应对象属性: {dir(response)}")
        
        if hasattr(response, 'output') and response.output:
            logger.info(f"输出对象: {response.output}")
            if hasattr(response.output, 'choices') and response.output.choices:
                logger.info(f"选择项数量: {len(response.output.choices)}")
                choice = response.output.choices[0]
                logger.info(f"第一个选择项: {choice}")
                if hasattr(choice, 'message') and hasattr(choice.message, 'content'):
                    content = choice.message.content
                    logger.info(f"消息内容: {content}")
                    if isinstance(content, list) and len(content) > 0:
                        # 查找文本内容和置信度
                        for i, item in enumerate(content):
                            logger.info(f"内容项 {i}: {item}")
                            if isinstance(item, dict):
                                if 'text' in item:
                                    text = item['text']
                                    logger.info(f"找到文本: {text}")
                                # 尝试提取置信度信息
                                if 'confidence' in item:
                                    confidence = float(item['confidence'])
                                    logger.info(f"找到置信度: {confidence}")
                                elif 'score' in item:
                                    confidence = float(item['score'])
                                    logger.info(f"找到分数: {confidence}")
                    else:
                        logger.warning(f"内容不是列表或为空: {content}")
                else:
                    logger.warning(f"选择项没有消息或内容: {choice}")
            else:
                logger.warning(f"输出没有选择项: {response.output}")
        else:
            logger.warning(f"响应没有输出: {response}")
        
        # 如果没有找到置信度，尝试从其他字段获取
        if confidence == 0.0 and hasattr(response, 'output') and response.output:
            try:
                # 检查是否有usage信息
                if hasattr(response, 'usage') and response.usage:
                    logger.info(f"使用情况: {response.usage}")
                # 检查是否有其他置信度字段
                if hasattr(response.output, 'confidence'):
                    confidence = float(response.output.confidence)
                    logger.info(f"从输出对象获取置信度: {confidence}")
                # 检查choices中是否有置信度信息
                if hasattr(response.output, 'choices') and response.output.choices:
                    choice = response.output.choices[0]
                    if hasattr(choice, 'confidence'):
                        confidence = float(choice.confidence)
                        logger.info(f"从选择项获取置信度: {confidence}")
                    # 检查message中是否有置信度
                    if hasattr(choice, 'message'):
                        message = choice.message
                        if hasattr(message, 'confidence'):
                            confidence = float(message.confidence)
                            logger.info(f"从消息获取置信度: {confidence}")
                        # 检查content中是否有置信度信息
                        if hasattr(message, 'content') and isinstance(message.content, list):
                            for item in message.content:
                                if isinstance(item, dict) and 'confidence' in item:
                                    confidence = float(item['confidence'])
                                    logger.info(f"从内容项获取置信度: {confidence}")
                                    break
            except Exception as e:
                logger.warning(f"获取置信度失败: {e}")
        
        # 如果仍然没有置信度，根据文本长度设置默认值
        if confidence == 0.0 and text:
            # 根据文本长度设置合理的默认置信度
            if len(text.strip()) > 0:
                confidence = 0.8  # 默认置信度
                logger.info(f"使用默认置信度: {confidence}")
        
        return {
            "task_id": task_id,
            "text": text,
            "confidence": confidence,
            "duration": duration,
            "timestamp": time.time(),
            "success": True,
            "raw_response": {
                "status_code": response.status_code,
                "message": getattr(response, 'message', ''),
                "output": getattr(response, 'output', None)
            }
        }
    
    async def recognize_audio_bytes(self, audio_bytes: bytes, task_id: str = None) -> Dict[str, Any]:
        """
        识别音频字节数据并返回文本结果
        
        Args:
            audio_bytes: 音频字节数据
            task_id: 任务ID，用于日志追踪
            
        Returns:
            Dict包含识别结果
        """
        start_time = time.time()
        log_function_call("ASRService.recognize_audio_bytes", {
            "audio_size": len(audio_bytes),
            "task_id": task_id
        })
        
        try:
            if not self.api_key:
                raise ValueError("ASR API key not configured")
            
            if len(audio_bytes) == 0:
                raise ValueError("Audio data is empty")
            
            logger.info(f"Starting ASR recognition for audio bytes, size: {len(audio_bytes)} bytes")
            
            # 记录ASR API调用
            log_api_call(
                api_name="QWEN3_ASR_DASHSCOPE_BYTES",
                api_type="ASR",
                request_data={
                    "audio_size": len(audio_bytes),
                    "task_id": task_id,
                    "model": self.model
                }
            )
            
            # 转换音频字节为base64
            audio_base64 = base64.b64encode(audio_bytes).decode('utf-8')
            
            # 构建消息
            messages = [
                {
                    "role": "system",
                    "content": [
                        {"text": ""},  # 系统提示词
                    ]
                },
                {
                    "role": "user",
                    "content": [
                        {"audio": f"data:audio/wav;base64,{audio_base64}"},
                    ]
                }
            ]
            
            # 调用DashScope API
            response = dashscope.MultiModalConversation.call(
                api_key=self.api_key,
                model=self.model,
                messages=messages,
                result_format="message",
                asr_options={
                    "enable_lid": True,  # 启用语言检测
                    "enable_itn": False  # 禁用逆文本规范化
                }
            )
            
            # 解析响应
            text = ""
            confidence = 0.0
            
            if response.status_code == 200:
                if hasattr(response, 'output') and response.output:
                    if hasattr(response.output, 'choices') and response.output.choices:
                        choice = response.output.choices[0]
                        if hasattr(choice, 'message') and hasattr(choice.message, 'content'):
                            content = choice.message.content
                            if isinstance(content, list) and len(content) > 0:
                                # 查找文本内容
                                for item in content:
                                    if isinstance(item, dict) and 'text' in item:
                                        text = item['text']
                                        break
            else:
                raise Exception(f"DashScope API error {response.status_code}: {response.message}")
            
            duration = (time.time() - start_time) * 1000
            log_function_result("ASRService.recognize_audio_bytes", {
                "text": text,
                "confidence": confidence
            }, duration)
            
            return {
                "task_id": task_id,
                "text": text,
                "confidence": confidence,
                "duration": duration / 1000.0,  # 转换为秒
                "timestamp": time.time(),
                "success": True,
                "raw_response": {
                    "status_code": response.status_code,
                    "message": getattr(response, 'message', ''),
                    "output": getattr(response, 'output', None)
                }
            }
            
        except Exception as e:
            duration = (time.time() - start_time) * 1000
            log_function_error("ASRService.recognize_audio_bytes", e, {
                "audio_size": len(audio_bytes),
                "task_id": task_id
            })
            logger.error(f"ASR recognition failed: {e}")
            
            return {
                "task_id": task_id,
                "text": "",
                "confidence": 0.0,
                "duration": 0.0,
                "timestamp": time.time(),
                "error": str(e),
                "success": False
            }
